﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Shutterstock.Salesforce.SSISDownload.SFTableOperations
{
    /// <summary>
    /// Represents an index 
    /// </summary>
    public class Index
    {
        #region Private Variables
        private string _indexName;
        private string _tableName;
        private bool _isUnique;
        private string _clustered;
        private SortedList<int, string> _columns;
        private List<string> _includedColumns;
        private string _partitionColumn;
        private List<string> _relationalIndexOptions;
        private string _dataSpaceName;
        #endregion

        #region Constructor
        /// <summary>
        /// Default Constructor
        /// </summary>
        public Index()
        {
            _indexName = string.Empty;
            _tableName = string.Empty;
            _isUnique = false;
            _clustered = "NONCLUSTERED";
            _columns = new SortedList<int, string>();
            _includedColumns = new List<string>();
            _partitionColumn = string.Empty;
            _relationalIndexOptions = new List<string>();
            _dataSpaceName = string.Empty;
        }
        #endregion
        
        #region Properties
        #region IndexName
        /// <summary>
        /// Get/Set properties of the Index Name
        /// </summary>
        public string IndexName
        {
            get { return _indexName; }
            set { _indexName = value; }
        }
        #endregion

        #region TableName
        /// <summary>
        /// Get/Set properties of the destination Table name
        /// </summary>
        public string TableName
        {
            get { return _tableName; }
            set { _tableName = value; }
        }
        #endregion

        #region IsUnique
        /// <summary>
        /// Get/Set properties of the is unique value
        /// </summary>
        public bool IsUnique
        {
            get { return _isUnique; }
            set { _isUnique = value; }
        }
        #endregion

        #region Clustered
        /// <summary>
        /// Get/Set properties of the Clustered value
        /// </summary>
        public string Clustered
        {
            get { return _clustered; }
            set { _clustered = value; }
        }
        #endregion

        #region DataSpaceName
        /// <summary>
        /// Get/Set properties of the Data space name: Partition_scheme_name, filegroup_name, default
        /// </summary>
        public string DataSpaceName
        {
            get { return _dataSpaceName; }
            set { _dataSpaceName = value; }
        }
        #endregion

        #region PartitionColumn
        /// <summary>
        /// Get/Set properties of the Partition column name
        /// </summary>
        public string PartitionColumn
        {
            get { return _partitionColumn; }
            set { _partitionColumn = value; }
        }
        #endregion

        #region RelationalIndexOptions
        /// <summary>
        /// Get property of RelationalIndexOptions
        /// </summary>
        public List<string> RelationalIndexOptions
        {
            get { return _relationalIndexOptions; }
        }
        #endregion

        #region IncludedColumns
        /// <summary>
        /// Get properties of IncludedColumns
        /// </summary>
        public List<string> IncludedColumns
        {
            get { return _includedColumns; }
        }
        #endregion

        #region Columns
        /// <summary>
        /// Get property of Columns: return a list of column names in order
        /// </summary>
        public List<string> Columns
        {
            get { return (List<string>)_columns.Values; }
        }
        #endregion
        
        #endregion

        #region Public Functions
        #region AddColumn
        /// <summary>
        /// Add column to the index
        /// </summary>
        /// <param name="key_ordinal"></param>
        /// <param name="column_name"></param>
        /// <param name="is_descending_key"></param>
        public void AddColumn(int key_ordinal, string column_name, bool is_descending_key)
        {
            if (is_descending_key)
            {
                this._columns.Add(key_ordinal, column_name + " DES");
            }
            else
            {
                this._columns.Add(key_ordinal, column_name + " ASC");
            }
        }
        #endregion

        #region AddIncludedColumn
        /// <summary>
        /// Add included column
        /// </summary>
        /// <param name="column_name"></param>
        public void AddIncludedColumn(string column_name)
        {
            this._includedColumns.Add(column_name);
        }
        #endregion

        #region SetRelationalIndexOptions
        /// <summary>
        /// Set Relational Index options
        /// </summary>
        /// <param name="ignore_dup_key"></param>
        /// <param name="fill_factor"></param>
        /// <param name="is_padded"></param>
        /// <param name="all_row_locks"></param>
        /// <param name="all_page_locks"></param>
        public void SetRelationalIndexOptions(bool ignore_dup_key, int fill_factor, 
            bool is_padded, bool all_row_locks,bool all_page_locks, DataCompression compressionOption)
        {
            // Default values:
            // PAD_INDEX = OFF,
            // FILLFACTOR = 0,
            // IGNORE_DUP_KEY = OFF,
            // ALLOW_ROW_LOCKS = ON,
            // ALLOW_PAGE_LOCKS ON 
            // DATA_COMPRESSION = NONE
            // only add Relational Index Options values when they are not default
            if (ignore_dup_key)
            {
                this._relationalIndexOptions.Add("IGNORE_DUP_KEY");
            }
            if (fill_factor != 0)
            {
                this._relationalIndexOptions.Add("FILLFACTOR = " + fill_factor.ToString());
            }
            if (is_padded)
            {
                this._relationalIndexOptions.Add("PAD_INDEX");
            }
            if (!all_page_locks)
            {
                this._relationalIndexOptions.Add("ALLOW_PAGE_LOCKS = OFF");
            }
            if (!all_row_locks)
            {
                this._relationalIndexOptions.Add("ALLOW_ROW_LOCKS = OFF");
            }
            if (compressionOption != DataCompression.None)
            {
                this._relationalIndexOptions.Add("DATA_COMPRESSION = " + compressionOption.ToString());
            }
        }
        #endregion

        #region CreateIndexQuery
        /// <summary>
        /// Return the query to creat the index
        /// </summary>
        /// <returns></returns>
        public string CreateIndexQuery()
        {
            StringBuilder query = new StringBuilder();
            query.Append("CREATE ");
            if (_isUnique)
            {
                query.Append("UNIQUE ");
            }
            query.AppendLine(_clustered + " INDEX [" + _indexName + "]");
            query.AppendLine("ON " + _tableName + " (" + ListToString(_columns) + ") ");
            if (_includedColumns.Count != 0)
            {
                query.AppendLine("INCLUDE (" + ListToString(_includedColumns) + ") ");
            }
            if (_relationalIndexOptions.Count != 0)
            {
                query.AppendLine("WITH ( " + ListToString(_relationalIndexOptions) + " )");
            }
            if (_dataSpaceName.Length != 0)
            {
                if (_partitionColumn.Length != 0)
                {
                    query.AppendLine("ON [" + _dataSpaceName + "]([" + _partitionColumn + "])");
                }
                else
                {
                    query.AppendLine("ON [" + _dataSpaceName + "]");
                }
            }
            return query.ToString();
        }
        #endregion
        #endregion

        #region Private Functions
        private string ListToString(List<string> list)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string s in list)
            {
                sb.Append(", " + s + "");
            }
            return sb.ToString().Length == 0 ? string.Empty : sb.ToString().Substring(2);
        }
        private string ListToString(SortedList<int, string> list)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string s in list.Values)
            {
                sb.Append(", " + s + "");
            }
            return sb.ToString().Length == 0 ? string.Empty : sb.ToString().Substring(2);
        }
        #endregion
    }
}

